﻿// <copyright file="MsdnXmlHandler.cs" company="Snowman Consulting">
//     Copyright (c) 2009 Snowman Consulting. All rights reserved.
// </copyright>

namespace SnowmanConsulting.ProductKeyManager.Xml
{
    using System;
    using System.Collections.Generic;
    using System.IO;
    using System.Linq;
    using System.Xml;
    using System.Xml.Linq;
    using SnowmanConsulting.ProductKeyManager.Data;

    /// <summary>
    /// XML Handler for the MSDN format key file.
    /// </summary>
    public class MsdnXmlHandler : IXmlHandler
    {
        /// <summary>
        /// Xml Root Node
        /// </summary>
        private const string RootNoteName = "Product_Key";

        #region IXmlHandler Members

        /// <summary>
        /// products collection
        /// </summary>
        private ProductCollection products;

        /// <summary>
        /// Generated xml field
        /// </summary>
        private string generatedXml;

        /// <summary>
        /// Gets the Products imported from the XML.
        /// </summary>
        /// <value>The Products.</value>
        public ProductCollection Products
        {
            get { return this.products; }
            private set { this.products = value; }
        }

        /// <summary>
        /// Gets the XML generated by from the Products.
        /// </summary>
        /// <value>The generated XML.</value>
        public string GeneratedXml
        {
            get { return this.generatedXml; }
        }

        /// <summary>
        /// Imports the XML.
        /// </summary>
        /// <param name="xml">The XML string.</param>
        public void Load(string xml)
        {
            XDocument document = XDocument.Load(new StringReader(xml));
            this.Load(document);
        }

        /// <summary>
        /// Imports the XML.
        /// </summary>
        /// <param name="fileUri">The file URI.</param>
        public void Load(Uri fileUri)
        {
            XDocument document = XDocument.Load(fileUri.ToString());
            this.Load(document);
        }

        /// <summary>
        /// Generates the XML.
        /// </summary>
        /// <param name="productCollection">The Products.</param>
        public void GenerateXml(ProductCollection productCollection)
        {
            this.GenerateXml(productCollection, false, string.Empty);
        }

        /// <summary>
        /// Generates the XML.
        /// </summary>
        /// <param name="productCollection">The Products.</param>
        /// <param name="generateStyleSheet">if set to <c>true</c> the stylesheet is generated.</param>
        /// <param name="fileName">Name of the file.</param>
        public void GenerateXml(ProductCollection productCollection, bool generateStyleSheet, string fileName)
        {
            string xmlResult = "<?xml version=\"1.0\" standalone=\"yes\" ?>" + Environment.NewLine;
            if (generateStyleSheet && !String.IsNullOrEmpty(fileName))
            {
                xmlResult += "<?xml-stylesheet type=\"text/xsl\" href=\"" + fileName + ".xsl\"?>" + Environment.NewLine;
            }

            List<XElement> elements = new List<XElement>();

            foreach (Product prod in productCollection)
            {
                foreach (ProductKey key in prod.Keys)
                {
                    XElement element = new XElement(
                        MsdnXmlHandler.RootNoteName,
                        new XAttribute("Name", prod.Name),
                        new XAttribute("Category", string.IsNullOrEmpty(prod.Category) ? string.Empty : prod.Category),
                        new XAttribute("Notes", string.IsNullOrEmpty(prod.Notes) ? string.Empty : prod.Notes),
                        new XAttribute("Key", key.Code),
                        new XAttribute("AllocatedTo", string.IsNullOrEmpty(key.AllocatedTo) ? string.Empty : key.AllocatedTo));
                    elements.Add(element);
                }
            }

            XElement xml = new XElement("Your_Product_Keys", elements.ToArray());

            this.generatedXml = xmlResult + xml.ToString();
        }

        /// <summary>
        /// Imports the XML.
        /// </summary>
        /// <param name="xmlDocument">The XML document.</param>
        public void Load(XDocument xmlDocument)
        {
            List<string> names = new List<string>();
            this.Products = new ProductCollection();

            IEnumerable<XElement> productKeyElements = xmlDocument.Descendants(MsdnXmlHandler.RootNoteName);

            foreach (XElement productKey in productKeyElements)
            {
                Product product;

                string name = string.Empty;
                string category = string.Empty;
                string notes = string.Empty;
                string key = string.Empty;
                string allocatedTo = string.Empty;

                XAttribute keyAttribute = productKey.Attribute("Key");
                if (keyAttribute != null)
                {
                    key = keyAttribute.Value;
                }

                XAttribute allocatedToAttribute = productKey.Attribute("AllocatedTo");
                if (allocatedToAttribute != null)
                {
                    allocatedTo = allocatedToAttribute.Value;
                }

                if (string.IsNullOrEmpty(allocatedTo))
                {
                    allocatedTo = "Not Allocated";
                }

                XAttribute nameAttribute = productKey.Attribute("Name");
                if (nameAttribute != null)
                {
                    name = nameAttribute.Value;

                    if (names.Contains(name))
                    {
                        Product existingProduct = (from ep in this.Products where ep.Name == name select ep).First();

                        if (existingProduct != null)
                        {
                            existingProduct.Keys.Add(new ProductKey { Code = key, AllocatedTo = allocatedTo });
                        }

                        continue;
                    }
                    else
                    {
                        names.Add(name);
                    }
                }
                else
                {
                    continue;
                }

                XAttribute categoryAttribute = productKey.Attribute("Category");
                if (categoryAttribute != null)
                {
                    category = categoryAttribute.Value;
                }

                XAttribute notesAttribute = productKey.Attribute("Notes");
                if (notesAttribute != null)
                {
                    notes = notesAttribute.Value;
                }

                product = new Product
                {
                    Name = name,
                    Category = category,
                    Notes = notes
                };

                product.Keys.Add(new ProductKey { Code = key, AllocatedTo = allocatedTo });

                this.Products.Add(product);
            }
        }

        #endregion
    }
}
